package com.dao.impl;

import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.dao.UniversalDao;
import com.vo.Page;

public class UniversalDaoImpl extends HibernateDaoSupport implements
		UniversalDao {

	private JdbcTemplate jdbcTemplate;

	public JdbcTemplate getJdbcTemplate() {
		return jdbcTemplate;
	}

	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}

	/**
	 * 增加记录到数据表中
	 * 
	 * @param object
	 */
	public void insert(Object o) {
		logger.debug("insert " + o.getClass().getSimpleName() + " instance");
		try {
			getHibernateTemplate().save(o);
			logger.debug("insert successful");
		} catch (RuntimeException re) {
			logger.error("insert failed", re);
			throw re;
		}

	}

	/**
	 * 更新记录到数据表中
	 * 
	 * @param object
	 */
	public void update(Object o) {
		logger.debug("update " + o.getClass().getSimpleName() + " instance");
		try {
			getHibernateTemplate().update(o);
			logger.debug("update successful");
		} catch (RuntimeException re) {
			logger.error("update failed", re);
			throw re;
		}
	}

	/**
	 * 更新记录到数据表中
	 * 
	 * @param object
	 */
	public void saveOrUpdate(Object o) {
		logger.debug("update " + o.getClass().getSimpleName() + " instance");
		try {
			getHibernateTemplate().saveOrUpdate(o);
			logger.debug("update successful");
		} catch (RuntimeException re) {
			logger.error("update failed", re);
			throw re;
		}
	}

	/**
	 * 根据主键删除一条数据库记录
	 * 
	 * @param object
	 */
	public void delete(Object o) {
		logger.debug("deleting " + o.getClass().getSimpleName() + " instance");
		try {
			getHibernateTemplate().delete(o);
			logger.debug("delete successful");
		} catch (RuntimeException re) {
			logger.error("delete failed", re);
			throw re;
		}
	}

	/**
	 * 获取数据表所有的记录
	 * 
	 * @param object
	 * @return list
	 */
	public List<Object> findAll(Class clazz) {
		logger.debug("finding all " + clazz.getSimpleName() + " instance");
		try {
			String queryString = "from " + clazz.getSimpleName();
			return getHibernateTemplate().find(queryString);
		} catch (RuntimeException re) {
			logger.error("find all failed", re);
			throw re;
		}
	}

	/**
	 * 根据主键从数据表中取回一个对象
	 * 
	 * @param clazz
	 * @param id
	 * @return object
	 */
	public Object findByID(Class clazz, Serializable id) {
		logger.debug("getting " + clazz.getName() + " instance with id: " + id);
		try {
			return getHibernateTemplate().get(clazz.getName(), id);
		} catch (RuntimeException re) {
			logger.error("get failed", re);
			throw re;
		}
	}

	/**
	 * 依据条件进行查找
	 * 
	 * @param clazz
	 * @param propertyName
	 * @param value
	 * @return list
	 */
	public List<Object> findByProperty(Class clazz, String propertyName,
			Object value) {
		logger.debug("finding " + clazz.getSimpleName()
				+ " instance with property: " + propertyName + ", value: "
				+ value);
		try {
			String queryString = "from " + clazz.getSimpleName()
					+ " as model where model." + propertyName + "= ?";
			// System.out.println(queryString);
			return getHibernateTemplate().find(queryString, value);
		} catch (RuntimeException re) {
			logger.error("find by property name failed", re);
			throw re;
		}
	}

	public void deleteAll(Collection entities) {
		logger.debug("deleting all instance");
		try {
			getHibernateTemplate().deleteAll(entities);
			logger.debug("delete successful");
		} catch (RuntimeException re) {
			logger.error("delete failed", re);
			throw re;
		}

	}

	/*
	 * @function 根据传递过来的Object,分页显示在数据库中与其匹配的记录
	 * 
	 * @param pageNo 当前页数
	 * 
	 * @param pageSize 每页显示的记录数
	 * 
	 * @param object 将查询条件封装为Object
	 * 
	 * @return 将查询结果封装为Page返回
	 */
	public Page findPageByExample(int pageNo, int pageSize, Object object) {
		Page page = null;
		logger.info(object);
		try {
			Criteria criteria = this.getSession().createCriteria(
					Class.forName(object.getClass().getName()));// this.getEntity()));
			if (object != null) {
				criteria.add(Example.create(object).enableLike());
			}
			// 获取根据条件分页查询的总行数
			int rowCount = (Integer) criteria.setProjection(
					Projections.rowCount()).uniqueResult();
			criteria.setProjection(null);
			criteria.setFirstResult((pageNo - 1) * pageSize);
			criteria.setMaxResults(pageSize);
			List result = criteria.list();
			page = new Page(pageSize, pageNo, rowCount, result);
		} catch (RuntimeException re) {
			re.printStackTrace();
			throw re;
		} finally {
			return page;
		}
	}

	/**
	 * @function 分页显示符合所有的记录数，将查询结果封装为Page
	 * @param pageNo
	 *            当前页数
	 * @param pageSize
	 *            每页显示的条数
	 * @param map
	 *            将查询条件封装为map
	 * @param clazz
	 * 
	 * @return 查询结果Page
	 */
	public Page findPageByCriteria(int pageNo, int pageSize, Map map,
			Class clazz) {
		Page page = null;
		logger.info(map);
		try {
			Criteria criteria = this.getSession().createCriteria(
					Class.forName(clazz.getName()));// this.getEntity()));
			if (map != null) {
				Set<String> keys = map.keySet();
				for (String key : keys) {
					criteria.add(Restrictions.like(key, map.get(key)));
				}
			}
			// 获取根据条件分页查询的总行数
			int rowCount = (Integer) criteria.setProjection(
					Projections.rowCount()).uniqueResult();
			criteria.setProjection(null);
			criteria.setFirstResult((pageNo - 1) * pageSize);
			criteria.setMaxResults(pageSize);
			List result = criteria.list();
			page = new Page(pageSize, pageNo, rowCount, result);
		} catch (RuntimeException re) {
			re.printStackTrace();
			throw re;
		} finally {
			return page;
		}
	}

	public Page findPageByCriteria(int pageNo, int pageSize, Map map,
			Map order, Class clazz) {
		Page page = null;
		logger.info(map);
		try {
			Criteria criteria = this.getSession().createCriteria(
					Class.forName(clazz.getName()));// this.getEntity()));
			if (map != null) {
				Set<String> keys = map.keySet();
				for (String key : keys) {
					criteria.add(Restrictions.like(key, map.get(key)));
				}
			}
			// 获取根据条件分页查询的总行数
			int rowCount = (Integer) criteria.setProjection(
					Projections.rowCount()).uniqueResult();
			criteria.setProjection(null);
			if (order != null) {
				String asc = (String) order.get("asc");
				String desc = (String) order.get("desc");
				String[] v = null;
				if (asc != null) {
					v = asc.split(",");
					for (String e : v)
						criteria.addOrder(Order.asc(e));
				} else if (desc != null) {
					v = desc.split(",");
					for (String e : v)
						criteria.addOrder(Order.desc(e));
				}
			}
			criteria.setFirstResult((pageNo - 1) * pageSize);
			criteria.setMaxResults(pageSize);
			List result = criteria.list();
			page = new Page(pageSize, pageNo, rowCount, result);
		} catch (RuntimeException re) {
			re.printStackTrace();
			throw re;
		} finally {
			return page;
		}
	}

	/**
	 * @function 分页显示符合所有的记录数，将查询结果封装为Pager
	 * @param pageNo
	 *            当前页数
	 * @param pageSize
	 *            每页显示的条数
	 * @param instance
	 *            将查询条件封装为专家Bean
	 * @return 查询结果Page
	 */
	public List<Object> findPageByQuery(int pageNo, int pageSize, String hql,
			Map map) {
		List<Object> result = null;
		try {
			Query query = this.getSession().createQuery(hql);

			Iterator it = map.keySet().iterator();
			while (it.hasNext()) {
				Object key = it.next();
				query.setParameter(key.toString(), map.get(key));
			}

			query.setFirstResult((pageNo - 1) * pageSize);
			query.setMaxResults(pageSize);

			result = query.list();

		} catch (RuntimeException re) {
			throw re;
		}
		return result;
	}

	/**
	 * @function 根据查询条件查询记录数的个数
	 * @param hql
	 *            hql查询语句
	 * @param map
	 *            用map封装查询条件
	 * @return 数据库中满足查询条件的数据的条数
	 */
	public int getTotalCount(String hql, Map map) {
		try {
			Query query = this.getSession().createQuery(hql);

			Iterator it = map.keySet().iterator();
			while (it.hasNext()) {
				Object key = it.next();
				query.setParameter(key.toString(), map.get(key));
			}

			Integer i = (Integer) query.list().get(0);
			return i;
		} catch (RuntimeException re) {
			throw re;
		}

	}

	public Page Page(int pageNo, int pageSize, String sql, String orderBy,
			Map param) {
		sql = sql.toLowerCase();
		String sqlCount = "select count(*) a "
				+ sql.substring(sql.indexOf(" from "));
		int length = param.size();
		Object[] objs = new Object[length];
		int i = 0;
		Iterator item = param.entrySet().iterator();
		while (item.hasNext()) {
			Map.Entry entry = (Map.Entry) item.next();
			Object key = entry.getKey();
			Object value = entry.getValue();
			sqlCount += " and " + key;
			sql += " and " + key;
			// System.out.println(key+"\t"+value);
			objs[i++] = value;
		}
		int rowCount = (Integer) getJdbcTemplate().queryForMap(sqlCount, objs)
				.get("a");
		int selectCount = pageNo * pageSize;
		if (selectCount > rowCount)
			selectCount = rowCount % pageSize;
		else
			selectCount = pageSize;
		sql = "select * from (select top " + selectCount
				+ " * from (select top " + (pageNo * pageSize) + " * from ("
				+ sql + ") tmp1 order by " + orderBy + " asc) tmp2 order by "
				+ orderBy + " desc) tmp3 order by " + orderBy + " asc";
		List list = getJdbcTemplate().queryForList(sql, objs);
		logger.info(sqlCount);
		logger.info(sql);
		for (Object v : objs)
			logger.info(v);
		Page page = new Page(pageSize, pageNo, rowCount, list);
		return page;
	}

	public Object getObject(String sql, Object[] param, Class clazz) {
		logger.info(sql);
		return getJdbcTemplate().queryForObject(sql, param, clazz);
	}

	public Map getMap(String sql, Object[] param) {
		logger.info(sql);
		return getJdbcTemplate().queryForMap(sql, param);
	}

	public void excuteSQL(String sql) {
		logger.info(sql);
		getJdbcTemplate().execute(sql);
	}

	public int excuteSQLForInt(String sql, Object[] obj) {
		logger.info(sql);
		return getJdbcTemplate().queryForInt(sql, obj);
	}

}
